#!/usr/bin/env python
# -*- coding:utf-8 -*-
# author:Vergil
# datetime:2018/11/1 9:33

from __future__ import print_function, division
import os
import random
import re
import time
import sys
import warnings
import psutil

import settings
from encoding import smart_unicode, DEFAULT_LOCALE_ENCODING

try:
    import wmi

    mainboard = wmi.WMI().Win32_BaseBoard()[0]
    cpu = wmi.WMI().Win32_Processor()[0]
    bios = wmi.WMI().Win32_Bios()[0]
    system = wmi.WMI().Win32_OperatingSystem()[0]
    memory = wmi.WMI().Win32_PhysicalMemory()[0]
    mem = wmi.WMI().Win32_ComputerSystem()[0]
except ImportError:
    warnings.warn(u'os不支持导入wmi', RuntimeWarning, stacklevel=2)


def get_base_infos():
    """ 获取计算机基本信息
    """
    try:
        cpu_version = cpu.Name
        mainboard_version = mainboard.Product
        mainboard_manufacturer = mainboard.Manufacturer
        host_name = system.CSName
        system_version = system.Caption
        memory_manufacturer = memory.Manufacturer
        memory_version = memory.PartNumber
        memory_total = str(
            round(int(mem.TotalPhysicalMemory) / 1024 ** 3, 2)) + 'G'
        return {'cpu': 'cpu_version:' + cpu_version,
                'mainboard': 'mainboard_version: %s, manufacturer: %s' % (mainboard_version,
                                                                          mainboard_manufacturer),
                'system': 'host_name: %s, version: %s'%(host_name, system_version),
                'memory': 'version: %s, manufacturer: %s, total: %s' % (memory_version,
                                                                        memory_manufacturer,
                                                                        memory_total)}
    except Exception as ex:
        print(ex)
        print(u'获取计算机基本信息失败{0}'.format(ex.message))


def get_cpu_infos():
    """ 获取cpu信息
    current_time：  时间
    cpu_percent： 使用率
    cpu_count：核心数
    cpu_thread：线程数
    cpu_temperature：温度
    """
    try:
        # current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        cpu_percent = psutil.cpu_percent(interval=0.1, percpu=True)
        # cpu_percent = cpu.LoadPercentage+8
        cpu_count = psutil.cpu_count(logical=False)
        cpu_thread = psutil.cpu_count()
        cpu_totalpercent = round(sum(x for x in cpu_percent) / int(cpu_thread), 2)
        cpu_dict = {
            'cpu_percent': cpu_percent,
            'cpu_totalpercent': cpu_totalpercent,
            'cpu_count': cpu_count,
            'cpu_thread': cpu_thread,
        }
        return cpu_dict
    except Exception as ex:
        print(u'获取cpu信息失败{0}'.format(ex.message))


def get_memory_infos():
    """ 获取内存信息字典
    m_used_percent：内存使用率
    m_total：内存总量，mb为单位
    m_used：已使用内存，mb为单位
    m_count：内存条数量
    m_physical_memory：内存容量数组，显示每根内存条的容量
    """
    try:
        m_physical_memory = []

        response = os.popen('wmic memorychip list brief').read()
        virtual_memory = psutil.virtual_memory()

        m_used_percent = virtual_memory.percent
        m_total = round(int(virtual_memory.total) / 1024**2)
        m_count = int(len(response.splitlines()) - 2)

        for i in range(0, int(m_count)):
            try:
                m_capacitys = re.findall(r'\s+(\d+)', response, re.S)
                m_capacity = m_capacitys[i * int(len(m_capacitys) / m_count)]
                m_tag = re.findall(r'\s\w+\s\w+\s\d', response, re.S)[i]
                m_physical_memory.append({m_tag: int(m_capacity) / 1024**2})
            except IndexError:
                return {'data': []}
            continue

        m_used = round(int(virtual_memory.used) / 1024**2)

        memory_dict = {
            'm_used_percent': m_used_percent,
            'm_total': m_total,
            'm_used': m_used,
            'm_physical_memory': m_physical_memory
        }

        return memory_dict
    except Exception as ex:
        print(u'获取内存信息失败{0}'.format(ex.message))


def get_disk_use_infos():
    """ 获取磁盘使用信息
    device：盘符,fstype：分区格式,d_total：总量,d_used：已使用空间,d_free：未使用空间,d_percent：使用百分比，使用量gb为单位
    """
    try:
        disk_use = {}

        disk_partitions = psutil.disk_partitions()
        for dp in disk_partitions:
            fstype = dp.fstype
            for device in dp.device[0]:
                try:
                    disk_usage = psutil.disk_usage('%s:/' % device)
                    disk_use[device] = {'fstype': fstype,
                                        'd_total': round(int(disk_usage.total) / 1024**3),
                                        'd_used': round(int(disk_usage.used) / 1024**3),
                                        'd_free': round(int(disk_usage.free) / 1024**3),
                                        'd_percent': disk_usage.percent
                                        }
                except OSError:
                    pass
        return disk_use
    except Exception as ex:
        print(u'获取磁盘使用信息失败{0}'.format(ex.message))


def get_dist_healthy_infos():
    """ 获取磁盘健康度
    name：属性名称,id：属性id,current：当前值,worst：最差值,value：数据
    """
    try:
        disk_healthy = {}

        smart_parameters = settings.SMART_PARAMETERS
        smart_id_lst = smart_parameters.keys()

        disk_lst = os.popen(
            'wmic diskdrive get serialnumber').read().splitlines()
        disk_lst = [d for d in disk_lst if d != '']

        for x in range(len(disk_lst) - 1):
            serial_number = disk_lst[x + 1].strip()
            healthy = {}
            response = os.popen('smartctl -a pd%d' % x).read()

            try:
                s_number = re.findall(
                    r'Serial Number:(.+)\nFirmware Version', response, re.S)[0].splitlines()[0].strip()
                data = re.findall(
                    r'RAW_VALUE\n(.+)\n\n\w*\s*SMART Error', response, re.S)
                datas = data[0].replace('\n', ' ').split()

                i = 0
                while i <= len(datas) - 10:
                    attribute = datas[i:i + 10]
                    id = attribute[0]
                    current = attribute[3]
                    worst = attribute[4]
                    threshold = attribute[5]
                    value = attribute[-1]
                    if id in smart_id_lst:
                        name = smart_parameters.get(id)
                        healthy[name] = {'id': id, 'current': current, 'worst': worst,
                                         'threshold': threshold, 'value': value}
                    i += 10

                disk_healthy[s_number + '_disk' + str(x)] = healthy

            except IndexError as e:
                pass
            except Exception as e:
                pass
        return disk_healthy
    except OSError as ex:
        print(u'获取磁盘健康度信息失败{0}'.format(ex.message))


def get_disk_infos():
    """ 获取磁盘信息,包括使用信息和健康度信息
    """
    return {
        'disk_use': get_disk_use_infos(),
        'disk_healthy': get_dist_healthy_infos()
    }


def _get_network_status():
    """ 获取网络状态
    """
    d = {}
    net_status = psutil.net_if_stats()
    for key in net_status.keys():
        isup = net_status[key].isup
        speed = net_status[key].speed
        d[key] = {'isup': isup, 'speed': speed}
    return d


def _get_network_io():
    """ 获取网络IO
    """
    d = {}
    net_io = psutil.net_io_counters(pernic=True)
    for key in net_io.keys():
        old_sent = net_io[key].bytes_sent
        old_recv = net_io[key].bytes_recv
        d[key] = {'sent': old_sent, 'recv': old_recv}

    return d


def get_network_infos():
    """ 获取网卡信息字典
    network_card：网卡名称
    mac：mac地址
    IPV4：IPV4地址
    IPV6：IPV6地址
    netmask：子网掩码
    isup：网线是否插入，True为插入，False为未插入
    speed：网卡接口传输速度，MB为单位
    net_percent：网络使用率
    sent：发送速度，kb为单位
    recv：接收速度，kb为单位
    """

    network_dict = {}
    network_lst = []
    network_card_lst = []

    try:
        network = psutil.net_if_addrs()
        encoding = sys.getfilesystemencoding()

        for key, value in network.items():
            network_card = key.decode(encoding=encoding)
            network_card_lst.append(network_card)

            try:
                if value[0].family == -1:
                    mac = value[0].address
                    ipv4 = value[1].address
                    netmask = value[1].netmask

                    network_dict[network_card] = {'mac': mac, 'ipv4': ipv4,
                                                  'netmask': netmask}
                elif value[0].family == 2:
                    mac = None
                    ipv4 = value[0].address
                    netmask = value[0].netmask

                    network_dict[network_card] = {'mac': mac, 'ipv4': ipv4,
                                                  'netmask': netmask}
            except IndexError:
                mac = value[0].address
                ipv4 = None
                netmask = value[0].netmask
                network_dict[network_card] = {'mac': mac, 'ipv4': ipv4,
                                              'netmask': netmask}
            except UnicodeDecodeError:
                pass

        network_status = _get_network_status()
        old_network_io = _get_network_io()
        time.sleep(1)
        network_io = _get_network_io()

        for x in network_io.keys():
            recv = network_io[x]['recv'] - old_network_io[x]['recv']
            sent = network_io[x]['sent'] - old_network_io[x]['sent']
            network_io[x].update({'recv': recv, 'sent': sent})

        for network_card in network_card_lst:
            for key in network_status.keys():
                if network_card == key.decode(encoding=encoding):
                    network_dict[network_card].update(network_status[key])
            for key in network_io.keys():
                if network_card == key.decode(encoding=encoding):
                    network_dict[network_card].update(network_io[key])
            try:
                net_percent = round((int(
                    network_dict[network_card]['sent']) + int(network_dict[network_card]['recv']))/ int(network_dict[network_card]['speed']) / 1024, 2)
                network_dict[network_card]['net_percent'] = net_percent
            except Exception:
                network_dict[network_card]['net_percent'] = None
                network_dict[network_card]['speed'] = None

        for key in network_dict.keys():
            try:
                network_lst.append(
                    dict({'network_card': key}, **network_dict[key]))
            except Exception:
                pass

        for n in network_lst:
            if n['ipv4'] == '127.0.0.1':
                network_lst.remove(n)
        return network_lst
    except Exception as ex:
        print(u'获取网络信息失败{0}'.format(ex.message))


def get_process_infos():
    """ 获取进程信息
    pid：进程id, name：进程名, cwd：进程工作目录, user：进程所属用户, ppid：父进程id,
    p_cpu_percent：cpu占用率, rss：进程使用内存, p_cpu_affinity：进程关联的cpu
    """
    process_list = []
    try:
        pids = psutil.pids()
        for pid in pids:
            try:
                p = psutil.Process(pid)
                cwd = smart_unicode(p.cwd(), DEFAULT_LOCALE_ENCODING)
                user = p.username()
                ppid = p.ppid()
                p.cpu_percent()
                time.sleep(0.1)
                p_cpu_percent = round(p.cpu_percent(interval=None) / psutil.cpu_count(), 2)
                memory_info = p.memory_info()
                name = smart_unicode(p.name(), DEFAULT_LOCALE_ENCODING)

                process_list.append({'name': name, 'pid': pid, 'cwd': cwd,
                                     'user': user, 'ppid': ppid, 'p_cpu_percent': p_cpu_percent,
                                     'rss': memory_info.rss})
            except psutil.AccessDenied:
                pass
            except psutil.NoSuchProcess:
                pass
            except psutil.TimeoutExpired:
                pass
        return process_list
    except Exception as ex:
        print(u'获取进程信息失败{0}'.format(ex.message))


if __name__ == '__main__':
    base = get_cpu_infos()
    print(base)
    # network = get_network_infos()
    # memory = get_memory_infos()
    # process = get_process_infos()
    # disk = get_disk_infos()
    raw_input('test finish')
